import os
import cv2
import json
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Optional, Tuple
from .logger import logger
from .config import config

class VideoProcessor:
    def __init__(self):
        self.supported_formats = config.get('video.allowed_formats', 
            [".mp4", ".avi", ".mov", ".wmv", ".flv", ".mkv"])

    def get_video_info(self, video_path: str) -> Optional[Dict]:
        """获取视频基本信息"""
        try:
            if not os.path.exists(video_path):
                raise FileNotFoundError("视频文件不存在")

            cap = cv2.VideoCapture(video_path)
            if not cap.isOpened():
                raise ValueError("无法打开视频文件")

            # 获取视频基本属性
            info = {
                "path": video_path,
                "filename": os.path.basename(video_path),
                "size": os.path.getsize(video_path),
                "create_time": datetime.fromtimestamp(
                    os.path.getctime(video_path)).isoformat(),
                "modify_time": datetime.fromtimestamp(
                    os.path.getmtime(video_path)).isoformat(),
                "format": os.path.splitext(video_path)[1].lower(),
                "width": int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),
                "height": int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)),
                "fps": cap.get(cv2.CAP_PROP_FPS),
                "frame_count": int(cap.get(cv2.CAP_PROP_FRAME_COUNT)),
                "duration": cap.get(cv2.CAP_PROP_FRAME_COUNT) / 
                           cap.get(cv2.CAP_PROP_FPS) if cap.get(cv2.CAP_PROP_FPS) > 0 else 0
            }

            cap.release()
            return info

        except Exception as e:
            logger.error(f"获取视频信息失败: {str(e)}")
            return None

    def convert_format(self, input_path: str, output_format: str) -> Optional[str]:
        """转换视频格式"""
        try:
            if not os.path.exists(input_path):
                raise FileNotFoundError("输入视频文件不存在")

            if not output_format.startswith('.'):
                output_format = '.' + output_format

            if output_format not in self.supported_formats:
                raise ValueError(f"不支持的输出格式: {output_format}")

            # 构建输出路径
            output_path = os.path.splitext(input_path)[0] + output_format

            # 读取输入视频
            cap = cv2.VideoCapture(input_path)
            if not cap.isOpened():
                raise ValueError("无法打开输入视频")

            # 获取视频属性
            width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
            fps = cap.get(cv2.CAP_PROP_FPS)

            # 创建视频写入器
            fourcc = cv2.VideoWriter_fourcc(*'mp4v')  # 默认使用MP4V编码
            out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))

            # 逐帧转换
            while cap.isOpened():
                ret, frame = cap.read()
                if not ret:
                    break
                out.write(frame)

            # 释放资源
            cap.release()
            out.release()

            logger.info(f"视频格式转换成功: {output_path}")
            return output_path

        except Exception as e:
            logger.error(f"视频格式转换失败: {str(e)}")
            return None

    def capture_thumbnail(self, video_path: str, time_offset: float = 0, 
                         output_path: Optional[str] = None) -> Optional[str]:
        """从视频中截取缩略图"""
        try:
            if not os.path.exists(video_path):
                raise FileNotFoundError("视频文件不存在")

            cap = cv2.VideoCapture(video_path)
            if not cap.isOpened():
                raise ValueError("无法打开视频文件")

            # 设置截取位置
            total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
            fps = cap.get(cv2.CAP_PROP_FPS)
            
            if time_offset > 0:
                frame_pos = int(time_offset * fps)
            else:
                frame_pos = int(total_frames * 0.5)  # 默认取中间帧
            
            frame_pos = min(frame_pos, total_frames - 1)
            cap.set(cv2.CAP_PROP_POS_FRAMES, frame_pos)

            # 读取帧
            ret, frame = cap.read()
            if not ret:
                raise ValueError("无法读取视频帧")

            # 生成输出路径
            if not output_path:
                output_path = os.path.splitext(video_path)[0] + "_thumb.jpg"

            # 保存缩略图
            cv2.imwrite(output_path, frame)
            cap.release()

            logger.info(f"视频缩略图生成成功: {output_path}")
            return output_path

        except Exception as e:
            logger.error(f"生成视频缩略图失败: {str(e)}")
            return None

    def extract_frames(self, video_path: str, output_dir: str, 
                      interval: float = 1.0) -> Optional[List[str]]:
        """按指定间隔提取视频帧"""
        try:
            if not os.path.exists(video_path):
                raise FileNotFoundError("视频文件不存在")

            # 确保输出目录存在
            os.makedirs(output_dir, exist_ok=True)

            cap = cv2.VideoCapture(video_path)
            if not cap.isOpened():
                raise ValueError("无法打开视频文件")

            fps = cap.get(cv2.CAP_PROP_FPS)
            frame_interval = int(fps * interval)
            frame_count = 0
            saved_frames = []

            while cap.isOpened():
                ret, frame = cap.read()
                if not ret:
                    break

                if frame_count % frame_interval == 0:
                    frame_path = os.path.join(
                        output_dir, 
                        f"frame_{frame_count:06d}.jpg"
                    )
                    cv2.imwrite(frame_path, frame)
                    saved_frames.append(frame_path)

                frame_count += 1

            cap.release()
            logger.info(f"视频帧提取完成，共{len(saved_frames)}帧")
            return saved_frames

        except Exception as e:
            logger.error(f"提取视频帧失败: {str(e)}")
            return None

    def save_metadata(self, video_path: str, metadata: Dict) -> bool:
        """保存视频元数据"""
        try:
            # 构建元数据文件路径
            meta_path = os.path.splitext(video_path)[0] + ".meta.json"
            
            # 添加时间戳
            metadata['update_time'] = datetime.now().isoformat()
            
            # 保存元数据
            with open(meta_path, 'w', encoding='utf-8') as f:
                json.dump(metadata, f, indent=4, ensure_ascii=False)
                
            logger.info(f"视频元数据保存成功: {meta_path}")
            return True

        except Exception as e:
            logger.error(f"保存视频元数据失败: {str(e)}")
            return False

    def load_metadata(self, video_path: str) -> Optional[Dict]:
        """加载视频元数据"""
        try:
            # 构建元数据文件路径
            meta_path = os.path.splitext(video_path)[0] + ".meta.json"
            
            if not os.path.exists(meta_path):
                return None
                
            # 读取元数据
            with open(meta_path, 'r', encoding='utf-8') as f:
                metadata = json.load(f)
                
            return metadata

        except Exception as e:
            logger.error(f"加载视频元数据失败: {str(e)}")
            return None

    def is_supported_format(self, file_path: str) -> bool:
        """检查是否为支持的视频格式"""
        ext = os.path.splitext(file_path)[1].lower()
        return ext in self.supported_formats

    def get_video_resolution(self, video_path: str) -> Optional[Tuple[int, int]]:
        """获取视频分辨率"""
        try:
            cap = cv2.VideoCapture(video_path)
            if not cap.isOpened():
                raise ValueError("无法打开视频文件")
                
            width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
            cap.release()
            
            return (width, height)

        except Exception as e:
            logger.error(f"获取视频分辨率失败: {str(e)}")
            return None

# 创建全局视频处理器实例
video_processor = VideoProcessor()

# 导出便捷函数
def get_video_info(video_path: str) -> Optional[Dict]:
    return video_processor.get_video_info(video_path)

def convert_format(input_path: str, output_format: str) -> Optional[str]:
    return video_processor.convert_format(input_path, output_format)

def capture_thumbnail(video_path: str, time_offset: float = 0, 
                     output_path: Optional[str] = None) -> Optional[str]:
    return video_processor.capture_thumbnail(video_path, time_offset, output_path)

def extract_frames(video_path: str, output_dir: str, 
                  interval: float = 1.0) -> Optional[List[str]]:
    return video_processor.extract_frames(video_path, output_dir, interval)

def save_metadata(video_path: str, metadata: Dict) -> bool:
    return video_processor.save_metadata(video_path, metadata)

def load_metadata(video_path: str) -> Optional[Dict]:
    return video_processor.load_metadata(video_path)

def is_supported_format(file_path: str) -> bool:
    return video_processor.is_supported_format(file_path)

def get_video_resolution(video_path: str) -> Optional[Tuple[int, int]]:
    return video_processor.get_video_resolution(video_path)
